package com.fw.system.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.db.Db;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fw.common.AliComm;
import com.fw.common.Builder;
import com.fw.common.IdXD;
import com.fw.constant.Constant;
import com.fw.core.redis.RedisCache;
import com.fw.core.text.StrFormatter;
import com.fw.enums.*;
import com.fw.system.comm.service.DistrictService;
import com.fw.system.comm.service.JdbcService;
import com.fw.system.web.dao.*;
import com.fw.system.web.model.entity.*;
import com.fw.system.web.model.form.ShopQuery;
import com.fw.system.web.model.form.ShopQuickQuery;
import com.fw.system.web.model.form.ShopRegisteredForm;
import com.fw.system.web.model.form.v2.ShopLoginForm;
import com.fw.system.web.model.vo.ShopAddVo;
import com.fw.system.web.model.vo.ShopKeywordVo;
import com.fw.system.web.model.vo.ShopOnLineVo;
import com.fw.system.web.model.vo.ShopVo;
import com.fw.system.web.model.vo.v2.ShopIsOffVo;
import com.fw.system.web.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fw.utils.*;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.fw.enums.CommodityStatusEnum.COMMODITY_STATUS_NO;
import static com.fw.enums.DisappearGetSourceEnum.SHOP_OFFLINE;
import static com.fw.enums.ShopStatus.PASS_SUCCESS;
import static com.fw.enums.ShopStatus.WAIT_PASS;

/**
 * <p>
 * 商铺表 服务实现类
 * </p>
 *
 * @author
 * @since 2021-05-10
 */
@Service
@RequiredArgsConstructor(onConstructor_={@Autowired} )
@Slf4j
public class FwShopServiceImpl extends ServiceImpl<FwShopMapper, FwShop> implements IFwShopService {

    private final IdXD idXD;

    private final RedisCache redisCache;

    private final FwOperatingMapper operatingMapper;

    private final FwPolMapper polMapper;

    private final FwShopMapper shopMapper;

    private  final DistrictService districtService;

    private final FwSpuMapper spuMapper;

    private final AliComm aliComm;

    private final FwUsjoinMapper usjoinMapper;

    private final FwUserMapper userMapper;

    private final IFwOfflineService offlineService;

    private final IFwRuleDatasService ruleDatasService;

    private final IFwMoneysService moneysService;


    private final IFwShopKeywordService shopKeywordService;

    private final FwEvaluationMapper evaluationMapper;


    private final IFwCurrencyLogService fwCurrencyLogService;

    private final FwRuleDatasMapper ruleDatasMapper;

    private final IFwLogsService logsService;

    private final JdbcService jdbcService;

    private final AuthUtils authUtils;
    private final FwOrderMapper orderMapper;


    /**
     * 注册商户主体
     * @param user
     * @param registeredForm
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void shopMerchant(FwUser user, ShopRegisteredForm registeredForm) {
        // 值验证
        Assert.isTrue(Objects.nonNull(operatingMapper.selectById(registeredForm.getOperatingName())) ,"商家经营分类不可为空");
        Assert.isTrue(Objects.isNull(getOne(Wrappers.<FwShop>lambdaQuery().eq(FwShop::getUserId,user.getId()).in(FwShop::getStatus,WAIT_PASS.getCode(), PASS_SUCCESS.getCode()))),"已有提交过的记录,不可重复提交！");
        // 商甲验证
        FwRuleDatas ruleDatas = ruleDatasService.getById(Constant.IsRuleData.SHOP_REGIS);
        Assert.isTrue(ruleDatas.getRuleCount().compareTo(registeredForm.getShangjia()) <=0 || ruleDatas.getRuleCount().compareTo(registeredForm.getOfflineShangjia()) <=0 ,String.format("当前注册商户线上线下需要质押商甲大于%s个起步.",ruleDatas.getRuleCount()));
        // 初始化商户状态基本信息。
        FwShop fwShop  = null;

        if (StringUtils.isNotBlank(registeredForm.getShopId()) && (fwShop =  getById(registeredForm.getShopId())) != null ){
            // 修改
        }else{
            fwShop = Builder.of(FwShop::new).build();
            // 新增
            fwShop.setId(idXD.nextId());
            // 生成商家编号
            fwShop.setShopHost(DateUtils.getDate().concat("-").concat(redisCache.getAddShopHost(Constant.RedisDistrict.SHOP_HOST)));
            // 分裂商家 poi 地位信息。
            created(registeredForm,fwShop.getId(),user.getId());
        }
        fwShop.setUserId(user.getId());
        // 商甲质押 - 线上
        shopShangjiaCustomer(fwShop,registeredForm,Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE);
        // 商甲质押 - 线下
        shopShangjiaCustomer(fwShop,registeredForm,Constant.ShopRuleData.SHOP_SHANGJIA_OFFLINE);
        fwShop.createD(user.getId());
        fwShop.setStatus(WAIT_PASS.getCode());
        BeanUtil.copyProperties(registeredForm,fwShop);
        saveOrUpdate(fwShop);
    }


    /**
     * 商甲 质押变更逻辑
     * @param oldShop
     * @param registeredForm
     */
    private void shopShangjiaCustomer(FwShop oldShop,ShopRegisteredForm registeredForm, String flag) {
        Assert.isTrue(Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE.equals(flag) || Constant.ShopRuleData.SHOP_SHANGJIA_OFFLINE.equals(flag),"flag error !");
        BigDecimal oldShopShangjia = null;
        BigDecimal newShangjia = null;
        if (Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE.equals(flag)){
            oldShopShangjia = Optional.ofNullable(oldShop.getShangjia()).orElse(new BigDecimal("0.000"));
            newShangjia = registeredForm.getShangjia();
        }else{
            oldShopShangjia = Optional.ofNullable(oldShop.getOfflineShangjia()).orElse(new BigDecimal("0.000"));
            newShangjia = registeredForm.getOfflineShangjia();
        }


        String userId = oldShop.getUserId();
        // 是否相等
        FwMoneys moneys = moneysService.getOne(Wrappers.<FwMoneys>lambdaQuery().eq(FwMoneys::getUserId, userId));
        if (oldShopShangjia.compareTo(newShangjia) != 0){
            // 1.商甲改变了开始处理.
            // 1.1商甲是增加了还是减少了.
            if (oldShopShangjia.compareTo(newShangjia) >= 1) {
                // 减少了
                // 查看当前发布的商品量是否能够满足减少质押条件。
                Integer spuCount = spuMapper.selectCount(Wrappers.<FwSpu>lambdaQuery().eq(FwSpu::getShopId,oldShop.getId()).eq(FwSpu::getStatus,COMMODITY_STATUS_NO.getCode()));
                // 查询对应规则表
                FwRuleDatas ruleDatas = ruleDatasService.getOne(Wrappers.<FwRuleDatas>lambdaQuery().eq(FwRuleDatas::getId, Constant.IsRuleData.SHOP_PUBLISH_SPU));
                BigDecimal ruleCount = ruleDatas.getRuleCount();
                // 减少的是否 满足当前商品的发布量
                BigDecimal resultPublishCount = ruleCount.multiply(new BigDecimal(spuCount));
                Assert.isTrue(newShangjia.compareTo(resultPublishCount) >=0,"不可减少商甲,需要将一些商品下架或删除!");
                // ok 开始减少，算出级差,返还到对应用户的 商甲表中.
                BigDecimal shangjiaRes = oldShopShangjia.subtract(newShangjia);
                moneys.setShangJia(moneys.getShangJia().add(shangjiaRes));
                moneysService.updateById(moneys);
                logsService.saveLogs(userId,userId, LogsTypeEnum.MONEY_INCOME, LogsModelEnum.SHANG_JIA_MODEL, StrFormatter.format("商户质押商品的商甲已经减少:{},此商甲已经返回钱包中!",shangjiaRes),shangjiaRes.toString());
               // fwCurrencyLogService.saveCurrencyAsync(shangjiaRes, CurrencyLogEnum.EXPAND,userId,CurrencyLogEnum.getShangjiaType());
                return;
            }
            // 增加了
            // 1.1 算出商甲级差
            BigDecimal shangjiaRes = newShangjia.subtract(oldShopShangjia);
            // 1.2 核实用户钱包的商甲是否够。
            Assert.isTrue(moneys.getShangJia().compareTo(shangjiaRes) >=0,"商甲不足,请充值后在质押!");
            moneys.setShangJia(moneys.getShangJia().subtract(shangjiaRes));
            moneysService.updateById(moneys);
            logsService.saveLogs(userId,userId, LogsTypeEnum.MONEY_CONSUMPTION, LogsModelEnum.SHANG_JIA_MODEL, StrFormatter.format("商户质押商品的商甲已经增加:{},请到后台管理发布商品!",shangjiaRes),shangjiaRes.toString());
            //fwCurrencyLogService.saveCurrencyAsync(shangjiaRes, CurrencyLogEnum.INCOME,userId,CurrencyLogEnum.getShangjiaType());

        }
    }

    /**
     * 根据用户经纬度查询附近商铺信息
     * @param shopQuery
     * @return
     */
    @Override
    public List<ShopOnLineVo> shopOnlineQuery(ShopQuery shopQuery,FwUser user) {
        // 个性化筛选条件
        List<ShopOnLineVo> shopOnLineVos = shopMapper.shopOnlineQuery(shopQuery);
        Set<String> shopIds = usjoinMapper.selectList(Wrappers.<FwUsjoin>lambdaQuery().select(FwUsjoin::getShopId).eq(FwUsjoin::getUserId, user.getId())).parallelStream().map(item2 -> item2.getShopId()).collect(Collectors.toSet());
        shopOnLineVos =   shopOnLineVos.parallelStream().filter(item ->{
            if (Objects.nonNull(user)){
                // 性别
                if (Objects.nonNull(user.getSex()) && Objects.nonNull(item.getDataSex()) && (!item.getDataSex().equals(2)))
                    return  item.getDataSex().equals(user.getSex());


                // 年龄 忽律
   /*             if (StringUtils.isNotBlank(user.getRangeMoney()) && StringUtils.isNotBlank(item.getDataIncome())){
                    String[] moneyRange = user.getRangeMoney().split("～");
                    String[] dataIncomeIds = item.getDataIncome().split("~");
                    if (moneyRange.length >=2 && dataIncomeIds.length >=2 && NumberUtil.isNumber(moneyRange[0]) &&  NumberUtil.isNumber(moneyRange[1]) && NumberUtil.isNumber(dataIncomeIds[0]) &&  NumberUtil.isNumber(dataIncomeIds[1])) {
                        return  Integer.parseInt( dataIncomeIds[0]) >=   Integer.parseInt(moneyRange[0]) || Integer.parseInt(dataIncomeIds[1])<=Integer.parseInt( moneyRange[1]) ;
                    }
                }*/
            }

            // 人均消费查询
            if (StringUtils.isNotBlank(shopQuery.getCustomSvgRange())){
                String[] customSvgRange = shopQuery.getCustomSvgRange().split(",");
                String shopSvg = item.getShopSvg();
                if (customSvgRange.length >=2 && StringUtils.isNotBlank(shopSvg) && NumberUtil.isNumber(customSvgRange[0]) &&  NumberUtil.isNumber(customSvgRange[1]) && NumberUtil.isNumber(shopSvg)) {
                    return  Integer.parseInt( customSvgRange[0]) <=   Integer.parseInt(shopSvg) && Integer.parseInt(customSvgRange[1])>=Integer.parseInt( shopSvg) ;
                }
            }
            return true;
        }).map( item ->{
            // 距离计算
            JSONObject jsonObject = HttpUtils.pol(shopQuery.getLongitude(), shopQuery.getLatitude(), item.getShopAddVo().getLongitude(), item.getShopAddVo().getLatitude());
            JSONObject poi = jsonObject.getJSONObject("route");
            if (Objects.nonNull(poi)){
                poi =      poi.getJSONArray("paths").getJSONObject(0);
                Integer distance = poi.getInteger("distance");
                Integer duration = poi.getInteger("duration");
                item.setStep(distance+"米");
                item.setStepTime(duration / 60 + "分钟");
            }
            // 地址转化
            item.getShopAddVo().setProvinceName(districtService.codeConversionName(item.getShopAddVo().getProvince()));
            item.getShopAddVo().setCityName(districtService.codeConversionName(item.getShopAddVo().getCity()));
            item.getShopAddVo().setAreaName(districtService.codeConversionName(item.getShopAddVo().getArea()));
            // 收藏
            item.setIsLike(0);
            if (Objects.nonNull(user)){
                if (shopIds.contains(item.getId())) {
                    item.setIsLike(1);
                }
            }
            return  item;
        } ).collect(Collectors.toList());



        return shopOnLineVos;
    }

    /**
     *
     * @param
     * @return
     */
    @Override
    public ShopVo shopDistance(String shopId, BigDecimal latitude, BigDecimal longitude,FwUser user) {
        ShopVo shopVo = new ShopVo();
        FwShop fwShop = getById(shopId);
        if (Objects.isNull(fwShop)) return null;
        BeanUtil.copyProperties(fwShop,shopVo);
        FwPol fwPol = polMapper.selectOne(Wrappers.<FwPol>lambdaQuery().eq(FwPol::getBusId, fwShop.getId()));
        // 计算 多少m ,多少 分钟
        if (Objects.nonNull(latitude) && Objects.nonNull(longitude) && latitude.doubleValue() != 0 && longitude.doubleValue() != 0){
            JSONObject jsonObject = HttpUtils.pol(longitude, latitude, fwPol.getLongitude(), fwPol.getLatitude());
            JSONObject poi = jsonObject.getJSONObject("route");
            if (Objects.nonNull(poi)){
                poi =      poi.getJSONArray("paths").getJSONObject(0);
                Integer distance = poi.getInteger("distance");
                Integer duration = poi.getInteger("duration");
                shopVo.setStep(distance+"米");
                shopVo.setStepTime(duration / 60 + "分钟");
            }
        }

        ShopAddVo shopAddVo = new ShopAddVo();
        BeanUtil.copyProperties(fwPol,shopAddVo);
        shopVo.setShopAddVo(shopAddVo);
        // 商户是否被当前用户收藏
        if (Objects.nonNull(user)){
            shopVo.setIsLike(0);
            if (Objects.nonNull(user)){
                Set<String> shopIds = usjoinMapper.selectList(Wrappers.<FwUsjoin>lambdaQuery().select(FwUsjoin::getShopId).eq(FwUsjoin::getUserId, user.getId())).parallelStream().map(item2 -> item2.getShopId()).collect(Collectors.toSet());
                if (shopIds.contains(shopVo.getId())) {
                    shopVo.setIsLike(1);
                }
            }
        }
        // 商户收藏量
        shopVo.setLikeCount(usjoinMapper.selectCount(Wrappers.<FwUsjoin>lambdaQuery().eq(FwUsjoin::getShopId,shopId)));
        // 地址转化
        shopVo.getShopAddVo().setProvinceName(districtService.codeConversionName(shopVo.getShopAddVo().getProvince()));
        shopVo.getShopAddVo().setCityName(districtService.codeConversionName(shopVo.getShopAddVo().getCity()));
        shopVo.getShopAddVo().setAreaName(districtService.codeConversionName(shopVo.getShopAddVo().getArea()));
        shopVo.setOId(shopVo.getOperatingName());
        shopVo.setOperatingName(operatingMapper.selectById(shopVo.getOperatingName()).getOperatingName());
        shopVo.setShopSpuVal(spuMapper.selectList(Wrappers.<FwSpu>lambdaQuery().eq(FwSpu::getShopId,shopId)).size());
        shopVo.setShopLikeVal(usjoinMapper.selectList(Wrappers.<FwUsjoin>lambdaQuery().eq(FwUsjoin::getShopId,shopId)).size());
        shopVo.setProcessVal(orderMapper.selectList(Wrappers.<FwOrder>lambdaQuery().eq(FwOrder::getShopId,shopId)).size());
        return shopVo;
    }

    /**
     * 商铺线下支付信息
     * 此操作不产生任何记录,因为二维码谁都能扫
     * %1 %2 %3 %4 %5
     * @param shopId
     * @param money
     * @param payType
     * @return
     */
    @SneakyThrows
    @Override
    public String offlineShop(String shopId, BigDecimal money, Integer payType,String userId) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userId",userId);
        jsonObject.put("shopId",shopId);
        String uuId = UUID.randomUUID().toString();
        return aliComm.appPay(uuId,money, AliPayEnum.shop_offline_pay,jsonObject.toJSONString());
    }

    /**
     * 线下支付成功
     * @param userId
     * @param shopId
     * @param money
     * 商户自己会设置让利比例, 百分比，我让利 %5，
     * 客户到店消费 100 ，商户得 95 且得 5 消证，然后，（ 5 * 6） = 消证给用户,并且推荐商户的这个人 直接拿 %n 根据身份得消证
     * 开始返回给消费者，上级第一级 根据  5 * 6 消证，的%10 开始返还，
     * 继续往上，按 %50 递减返还。
     */
    @Override
   // @Transactional(rollbackFor = Exception.class)
    public void offlinePaySuccess(String userId, String shopId, BigDecimal money) {
        // 拿到商户的线下让利的百分比 开始反消证.
        FwShop fwShop = getById(shopId);
        // 直接给商户转账,钱直接给商户
        // 钱根据商户的让利比，进行让利。
        BigDecimal lineCustomer = fwShop.getLineCustomer();
        // 拿到让利比利润
        BigDecimal realAmount =  RandomUtils.mathNumber(lineCustomer,money);
        try {
            FwUser fwUser = userMapper.selectById(fwShop.getUserId());
            if (money.compareTo(realAmount) != 0)
            aliComm.aliTransfer(fwUser.getAliPhone(),RandomUtils.runodMath(money.subtract(realAmount)),fwUser.getAliUserName());

            offlineService.shopSave(userId,shopId,money,realAmount, PayTypeEnum.PAY_ALI,"正常入账");
        } catch (Exception e) {
            offlineService.shopSave(userId,shopId,money,realAmount, PayTypeEnum.PAY_ALI,e.getMessage());
            log.error("商户线下消费支付失败,商户编号:{},用户付款金额:{},错误原因:{}.",shopId,RandomUtils.runodMath(realAmount),e.getMessage());
            //e.printStackTrace();
            // throw new RuntimeException("roll_back");
        }
        // 补单 也需要 反给用户消证
        // 开始返消证给用户，以及商户。
        // 1.1 商户得到的消证
        BigDecimal shopDisappear =  realAmount;
        if (money.compareTo(realAmount) == 0)
            shopDisappear = money;
        moneysService.shopDisappearReturn(fwShop,shopDisappear,shopDisappear.toString(),"用户线下消费商户获取消证{}");
        // moneysService.disappearReturnParent(fwShop.getUserId(),shopDisappear,SHOP_OFFLINE.getSourceInfo());
        // 1.2 用户得消证 放大 ? 倍
        FwRuleDatas ruleDatas = ruleDatasService.getOne(Wrappers.<FwRuleDatas>lambdaQuery().eq(FwRuleDatas::getId, Constant.IsRuleData.SHOP_OFFLINE_ID));
        BigDecimal userDisappear = shopDisappear.multiply(ruleDatas.getRuleCount());
        log.info("当前用户消证为:{},原始消证:{},乘积:{}",userDisappear,shopDisappear,ruleDatas.getRuleCount());
        moneysService.disappearReturn(userId,userDisappear.setScale(3,BigDecimal.ROUND_DOWN),"线下消费送消证");

    }

    @Override
    public ShopVo selectByUserId(String userId) {
        FwShop shop = null;
        ShopVo shopVo = null;
        if ((shop = getOne(Wrappers.<FwShop>lambdaQuery().eq(FwShop::getUserId, userId))) != null){
            shopVo = shopDistance(shop.getId(),null,null,null);
        }
        return shopVo;
    }

    @Override
    public List<ShopKeywordVo> queryKeyWord(String shopId) {
        List<FwShopKeyword> fwShopKeywords = shopKeywordService.list(Wrappers.<FwShopKeyword>lambdaQuery().eq(FwShopKeyword::getShopId, shopId));
        return fwShopKeywords.parallelStream().map(item -> {
            ShopKeywordVo fwShopKeyword = Builder.of(ShopKeywordVo::new).build();
            BeanUtil.copyProperties(item,fwShopKeyword);
            return  fwShopKeyword;
        }).collect(Collectors.toList());
    }

    /**
     * 商铺打分计算
     * @param itemId
     * @param star
     *
     */
    @Override
    public void svgStore(String itemId, Integer star) {
        // 拿到所有评价的星等级
        List<FwEvaluation> fwEvaluations = evaluationMapper.selectList(Wrappers.<FwEvaluation>lambdaQuery().eq(FwEvaluation::getItemId, itemId));
        if (fwEvaluations.size() != 0) {
            int num = fwEvaluations.parallelStream().map(item -> item.getStarNum()).reduce(Integer::sum).get() + star;
            int count = fwEvaluations.size() + 1;
            FwSpu fwSpu = spuMapper.selectById(itemId);
            if (fwSpu == null) {return;}
            FwShop fwShop = getById(fwSpu.getShopId());
            fwShop.setShopScore( NumberUtil.partValue(num,count,Boolean.TRUE) % 5 );
            updateById(fwShop);
        }
    }




    /**
     * 新增poi 信息
     * @param registeredForm
     * @param shopId
     */
    private void created(ShopRegisteredForm registeredForm, String shopId,String userId) {
        FwPol selectOne = polMapper.selectOne(Wrappers.<FwPol>lambdaQuery().eq(FwPol::getBusId, shopId));
        if (selectOne == null){
            selectOne = new FwPol();
            selectOne.setId(idXD.nextId());
        }else{
            polMapper.deleteById(selectOne.getId());
        }
        selectOne.setBusId(shopId);
        selectOne.createD(userId);
        // 初始化 poi 后，经纬度肯定是空的
        BeanUtil.copyProperties(registeredForm,selectOne);
        polMapper.insert(selectOne);

    }


    /**
     * 发布商品的时候 商家是否有充裕 商甲发布
     * @param shopId 商铺编号
     * @param flag  是否线上还是线下 商品  Constant.ShopRuleData
     */
    @Override
    public void shopPublishSpu(String shopId,String flag){
        Assert.isTrue(Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE.equals(flag) || Constant.ShopRuleData.SHOP_SHANGJIA_OFFLINE.equals(flag),"flag error !");
        FwShop oldShop = getById(shopId);
        BigDecimal oldShopShangjia = null;
        String roleData = Constant.IsRuleData.SHOP_PUBLISH_SPU;
        String spuIsOffline = SpuEnum.SPU_ON.getCode();
        if (Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE.equals(flag)){
            // 线上商甲质押
            oldShopShangjia = Optional.of(oldShop.getShangjia()).orElse(new BigDecimal("0.000"));
        }else{
            // 线下商甲质押
            oldShopShangjia = Optional.of(oldShop.getOfflineShangjia()).orElse(new BigDecimal("0.000"));
            spuIsOffline = SpuEnum.SPU_OFF.getCode();
            roleData = Constant.IsRuleData.SHOP_OFF_PUBLISH_SPU;
        }
        // 查看当前发布的商品量是否能够满足减少质押条件, 分为线上，还是线下
        Integer spuCount = spuMapper.selectCount(Wrappers.<FwSpu>lambdaQuery().eq(FwSpu::getShopId,oldShop.getId()).eq(FwSpu::getStatus,COMMODITY_STATUS_NO.getCode()).eq(FwSpu::getIsOffline,spuIsOffline));
        // 查询对应规则表
        FwRuleDatas ruleDatas = ruleDatasMapper.selectOne(Wrappers.<FwRuleDatas>lambdaQuery().eq(FwRuleDatas::getId, roleData));
        BigDecimal ruleCount = ruleDatas.getRuleCount();
        // 减少的是否 满足当前商品的发布量 现有商甲 * 规则数 = 可发布的商品量
        BigDecimal maxSpuCount = oldShopShangjia.multiply(ruleCount);
        Assert.isTrue(maxSpuCount.compareTo(NumberUtil.add(spuCount)) >=0,"商甲不足,请到用户端抢购商甲!");
    }


    /**
     * 商甲 质押变更逻辑
     * @param oldShop
     * @param newShop
     */
    @Override
    public void shopShangjiaCustomer(FwShop oldShop, FwShop newShop, String flag) {
        Assert.isTrue(Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE.equals(flag) || Constant.ShopRuleData.SHOP_SHANGJIA_OFFLINE.equals(flag), "flag error !");
        BigDecimal oldShopShangjia = null;
        BigDecimal newShangjia = null;
        if (Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE.equals(flag)) {
            oldShopShangjia = Optional.of(oldShop.getShangjia()).orElse(new BigDecimal("0.000"));
            newShangjia = newShop.getShangjia();
        } else {
            oldShopShangjia = Optional.of(oldShop.getOfflineShangjia()).orElse(new BigDecimal("0.000"));
            newShangjia = newShop.getOfflineShangjia();
        }


        String userId = oldShop.getUserId();
        // 是否相等
        FwMoneys moneys = moneysService.getOne(Wrappers.<FwMoneys>lambdaQuery().eq(FwMoneys::getUserId, userId));
        if (oldShopShangjia.compareTo(newShangjia) != 0) {
            // 1.商甲改变了开始处理.
            // 1.1商甲是增加了还是减少了.
            if (oldShopShangjia.compareTo(newShangjia) >= 1) {
                // 减少了
                // 查看当前发布的商品量是否能够满足减少质押条件。
                Integer spuCount = spuMapper.selectCount(Wrappers.<FwSpu>lambdaQuery().eq(FwSpu::getShopId, oldShop.getId()).eq(FwSpu::getStatus, COMMODITY_STATUS_NO.getCode()));
                // 查询对应规则表
                FwRuleDatas ruleDatas = ruleDatasMapper.selectOne(Wrappers.<FwRuleDatas>lambdaQuery().eq(FwRuleDatas::getId, Constant.IsRuleData.SHOP_PUBLISH_SPU));
                BigDecimal ruleCount = ruleDatas.getRuleCount();
                // 减少的是否 满足当前商品的发布量
                BigDecimal resultPublishCount = ruleCount.multiply(new BigDecimal(spuCount));
                Assert.isTrue(newShangjia.compareTo(resultPublishCount) >= 0, "不可减少商甲,需要将一些商品下架或删除!");
                // ok 开始减少，算出级差,返还到对应用户的 商甲表中.
                BigDecimal shangjiaRes = oldShopShangjia.subtract(newShangjia);
                moneys.setShangJia(moneys.getShangJia().add(shangjiaRes));
                moneysService.updateById(moneys);
                 logsService.saveLogs(userId,userId, LogsTypeEnum.MONEY_INCOME, LogsModelEnum.SHANG_JIA_MODEL, StrFormatter.format("商户质押商品的商甲已经减少:{},此商甲已经返回钱包中!",shangjiaRes),shangjiaRes.toString());
                //currencyLogService.saveCurrencyAsync(shangjiaRes, CurrencyLogEnum.EXPAND, userId, CurrencyLogEnum.getShangjiaType());

                return;
            }
            // 增加了
            // 1.1 算出商甲级差
            BigDecimal shangjiaRes = newShangjia.subtract(oldShopShangjia);
            // 1.2 核实用户钱包的商甲是否够。
            Assert.isTrue(moneys.getShangJia().compareTo(shangjiaRes) >= 0, "商甲不足,请充值后在质押!");
            moneys.setShangJia(moneys.getShangJia().subtract(shangjiaRes));
            moneysService.updateById(moneys);
            logsService.saveLogs(userId,userId, LogsTypeEnum.MONEY_CONSUMPTION, LogsModelEnum.SHANG_JIA_MODEL, StrFormatter.format("商户质押商品的商甲已经增加:{},请到后台管理发布商品!",shangjiaRes),shangjiaRes.toString());
            //currencyLogService.saveCurrencyAsync(shangjiaRes, CurrencyLogEnum.INCOME, userId, CurrencyLogEnum.getShangjiaType());

        }
    }

    @Override
    public Object shopLogin(ShopLoginForm shopLoginForm) {
        // 开始登录
        String phone = shopLoginForm.getPhone();
        String passWord = shopLoginForm.getPassWord();
        FwUser fwUser = userMapper.selectOne(Wrappers.<FwUser>lambdaQuery().eq(FwUser::getPhone,phone));
        Assert.isTrue(Objects.nonNull(fwUser),"商户账号错误!");
        // 匹配密码 支持 app 和 admin 端 密码通用
        String adminPwd = jdbcService.findAdminPwd(phone);
        Assert.isTrue(Objects.nonNull(isShop(fwUser.getId())) && StringUtils.isNotBlank(adminPwd),"当前用户暂未注册商户,请核实!");
        Assert.isTrue(passWord.equals(fwUser.getPassWord()) || SecurityUtils.matchesPassword(passWord,adminPwd),"密码错误,请核实!");
        // 返回 token
        return  authUtils.createJWT(fwUser.getId(), "", null);
    }

    /**
     * 是否是商铺,不是返回 null
     * @param userId
     * @return
     */
    @Override
    public ShopVo isShop(String userId){
        return selectByUserId(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object edit(ShopVo shopVo) {
        changeLatLnt(shopVo);
        FwShop shop = new FwShop();
        BeanUtil.copyProperties(shopVo, shop);
        FwShop oldShop = getById(shopVo.getId());
        // 商甲质押 - 线上
        shopShangjiaCustomer(oldShop,shop, Constant.ShopRuleData.SHOP_SHANGJIA_ONLINE);
        // 商甲质押 - 线下
        shopShangjiaCustomer(oldShop,shop,Constant.ShopRuleData.SHOP_SHANGJIA_OFFLINE);
        // 如果是线下 必须让利 超过百分之20 以及
 /*       if (shop.getOfflineShangjia().compareTo(NumberUtil.add(0D)) > 0){
            // 是一个线下商户
            Assert.isTrue(shop.getLineCustomer().compareTo(NumberUtil.add(20D)) >= 0,"线下商户必须让利 百分之20及以上！");
        }*/
       return updateById(shop);

    }

    // 线上 还是线下
    @Override
    public ShopIsOffVo isOff(String shopId) {
        ShopIsOffVo shopIsOffVo = new ShopIsOffVo();
        shopIsOffVo.setIsOff(shopOff(shopId));
        shopIsOffVo.setIsOnline(shopOnline(shopId));
        return shopIsOffVo;
    }

    // 判断是否是线上商户  TRUR 是 FALSE 不是
    @Override
    public Boolean shopOnline(String shopId){
        FwShop shop = getById(shopId);
        return shop.getShangjia().compareTo(NumberUtil.add(0D)) >=1;
    }

    // 判断是否是线下商户  TRUR 是 FALSE 不是
    @Override
    public Boolean shopOff(String shopId){
        FwShop shop = getById(shopId);
        return shop.getOfflineShangjia().compareTo(NumberUtil.add(0D)) >=1;
    }

    /**
     * 经纬度判断
     */
    private void changeLatLnt(ShopVo shopVo) {
        //更新经纬度，地址
            ShopAddVo shopAddVo = shopVo.getShopAddVo();
            FwPol fwPol = polMapper.selectOne(Wrappers.<FwPol>lambdaQuery().eq(FwPol::getBusId, shopVo.getId()));
            fwPol.setLatitude(shopAddVo.getLatitude());
            fwPol.setLongitude(shopAddVo.getLongitude());
            fwPol.updateD(shopVo.getUserId());
            fwPol.setProvince(shopAddVo.getProvince());
            fwPol.setCity(shopAddVo.getCity());
            fwPol.setArea(shopAddVo.getArea());
            fwPol.setAddrInfo(shopAddVo.getAddrInfo());
            polMapper.updateById(fwPol);
    }

}
